package TestFiles;
import graphdisplay.AbstractGraph;
import graphdisplay.Displayable;
import graphdisplay.Graph;
import graphdisplay.WeightedEdge;
import graphdisplay.WeightedGraph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import TestFiles.DisplayUSMap.City;

public class DynamicWeitedGraph extends JApplet {
  private JTextField jtfVertexName = new JTextField(5);
  private JTextField jtfX = new JTextField(5);
  private JTextField jtfY = new JTextField(5);
  private JButton jbtAddVertex = new JButton("Add Vertex");
  
  private JTextField jtfu = new JTextField(5);
  private JTextField jtfv = new JTextField(5);
  private JTextField jtfWeight = new JTextField(5);
  private JButton jbtAddEdge = new JButton("Add Edge");

  
  private JTextField shrstart= new JTextField(5);
  private JTextField shrend = new JTextField(5);
  private JButton shrpath = new JButton("Shortest Path");

  private JButton importing = new JButton("Import");
  private JButton export = new JButton("Export");
  public JLabel c1= new JLabel("File Path");

  List<Vertex> verticeslist = new ArrayList<Vertex>();
  List<WeightedEdge> edgeslist = new ArrayList<WeightedEdge>();

 
  
  


  private WeightedGraph<Vertex> graph; //= new WeightedGraph<Vertex>(edges,vertices);
  private GraphView view; //= new GraphView(graph);
  
  public DynamicWeitedGraph() {
    JPanel panel1 = new JPanel(new GridLayout(4, 2));
    panel1.add(new JLabel("Vertex name: "));
    panel1.add(jtfVertexName);
    panel1.add(new JLabel("x-coordinate: "));
    panel1.add(jtfX);
    panel1.add(new JLabel("y-coordinate: "));
    panel1.add(jtfY);
    panel1.add(new JLabel());
    panel1.add(jbtAddVertex);
    panel1.setBorder(new TitledBorder("Add a new vertex"));
    
    JPanel panel2 = new JPanel(new GridLayout(4, 2));
    panel2.add(new JLabel("Vertex u (index): "));
    panel2.add(jtfu);
    panel2.add(new JLabel("Vertex v (index): "));
    panel2.add(jtfv);
    panel2.add(new JLabel("Weight (int): "));
    panel2.add(jtfWeight);
    panel2.add(new JLabel(""));
    panel2.add(jbtAddEdge);
    panel2.setBorder(new TitledBorder("Add a new edge"));

    
    
    JPanel panelShr = new JPanel(new GridLayout(3, 2));
    panelShr.add(new JLabel("Starting Vertex (index): "));
    panelShr.add(shrstart);
    panelShr.add(new JLabel("Ending Vertex (index): "));
    panelShr.add(shrend);
    panelShr.add(new JLabel(""));
    panelShr.add(shrpath);
    panelShr.setBorder(new TitledBorder("Find a Shortest Path"));
    
    JPanel panelimp = new JPanel(new GridLayout(2, 2));
    panelimp.add(importing);
    panelimp.add(export);
    panelimp.add(c1);
    panelimp.setBorder(new TitledBorder("Import/Export"));
  
    
    
    
    JPanel panel4 = new JPanel(new GridLayout(1, 2));
    panel4.add(panel1);
    panel4.add(panel2);
    panel4.add(panelShr);
    panel4.add(panelimp);
    
    JPanel panel5 = new JPanel(new BorderLayout());
    panel5.add(panel4);

   
    
    verticeslist.add(new Vertex("0 Seattle", 75, 50));
    verticeslist.add(new Vertex("1 San Francisco", 50, 210));
    verticeslist.add(new Vertex("2 Los Angeles", 75, 275));
    verticeslist.add(new Vertex("3 Denver", 275, 175));
    verticeslist.add(new Vertex("4 Kansas City", 400, 245));
    verticeslist.add(new Vertex("5 Chicago", 450, 100));
    verticeslist.add(new Vertex("6 Boston", 700, 80));
    verticeslist.add(new Vertex("7 New York", 675, 120));
    verticeslist.add(new Vertex("8 Atlanta", 575, 295));
    verticeslist.add(new Vertex("9 Miami", 600, 400));
    verticeslist.add(new Vertex("10 Dallas", 408, 325));
    verticeslist.add(new Vertex("11 Houston", 450, 360));
    
    

  
    // Edge array for graph in Figure 27.1
    edgeslist.add(new WeightedEdge(0, 1,807));
    edgeslist.add(new WeightedEdge(0, 3,1331));
    edgeslist.add(new WeightedEdge(0, 5,2097));

    edgeslist.add(new WeightedEdge(1, 0,807));
    edgeslist.add(new WeightedEdge(1, 2,381));
    edgeslist.add(new WeightedEdge(1, 3,1267));

    edgeslist.add(new WeightedEdge(2, 1,381));
    edgeslist.add(new WeightedEdge(2, 3,1015));
    edgeslist.add(new WeightedEdge(2, 4,1663));
    edgeslist.add(new WeightedEdge(2, 10,1435));

    edgeslist.add(new WeightedEdge(3, 0,1331));
    edgeslist.add(new WeightedEdge(3, 1,1267));
    edgeslist.add(new WeightedEdge(3, 2,1015));
    edgeslist.add(new WeightedEdge(3, 4,599));
    edgeslist.add(new WeightedEdge(3, 5,1003));

    edgeslist.add(new WeightedEdge(4, 2,1663));
    edgeslist.add(new WeightedEdge(4, 3,599));
    edgeslist.add(new WeightedEdge(4, 5,533));
    edgeslist.add(new WeightedEdge(4, 7,1260));
    edgeslist.add(new WeightedEdge(4, 8,864));
    edgeslist.add(new WeightedEdge(4, 10,496));

    edgeslist.add(new WeightedEdge(5, 0,2097));
    edgeslist.add(new WeightedEdge(5, 3,1003));
    edgeslist.add(new WeightedEdge(5, 4,533));
    edgeslist.add(new WeightedEdge(5, 6,983));
    edgeslist.add(new WeightedEdge(5, 7,787));

    edgeslist.add(new WeightedEdge(6, 5,983));
    edgeslist.add(new WeightedEdge(6, 7,214));

    edgeslist.add(new WeightedEdge(7, 4,1260));
    edgeslist.add(new WeightedEdge(7, 5,787));
    edgeslist.add(new WeightedEdge(7, 6,214));
    edgeslist.add(new WeightedEdge(7, 8,888));

    edgeslist.add(new WeightedEdge(8, 4,864));
    edgeslist.add(new WeightedEdge(8, 7,888));
    edgeslist.add(new WeightedEdge(8, 9,661));
    edgeslist.add(new WeightedEdge(8, 10,781));
    edgeslist.add(new WeightedEdge(8, 11,810));

    edgeslist.add(new WeightedEdge(9, 8,661));
    edgeslist.add(new WeightedEdge(9, 11,1187));

    edgeslist.add(new WeightedEdge(10, 2,1435));
    edgeslist.add(new WeightedEdge(10, 4,496));
    edgeslist.add(new WeightedEdge(10, 8,781));
    edgeslist.add(new WeightedEdge(10, 11,239));

    edgeslist.add(new WeightedEdge(11, 8,810));
    edgeslist.add(new WeightedEdge(11, 9,1187));
    edgeslist.add(new WeightedEdge(11, 10,239));
    
    graph = new WeightedGraph<Vertex>(edgeslist,verticeslist);
    view = new GraphView(graph);
    add(new JScrollPane(view));
    add(panel5, BorderLayout.SOUTH);
    
    jbtAddVertex.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        String name = jtfVertexName.getText();
                
          int x = Integer.parseInt(jtfX.getText().trim());
          int y = Integer.parseInt(jtfY.getText().trim());
          
          graph.addVertex(new Vertex(verticeslist.size()+ " "  +name, x, y));
          view.repaint();
         // System.out.print("no of vertces = " + verticeslist.size());
	    
      }
    }
    );   
    
    jbtAddEdge.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        int u = Integer.parseInt(jtfu.getText().trim());
        int v = Integer.parseInt(jtfv.getText().trim());
        double weight = Double.parseDouble(jtfWeight.getText().trim());

        if (u < 0 || u >= graph.getSize())
          JOptionPane.showMessageDialog(
            null, "Vertex " + u + " is not in the graph"+"it must be less than "+graph.getSize());
        else if (v < 0 || v >= graph.getSize())
          JOptionPane.showMessageDialog(
            null, "Vertex " + v + " is not in the graph"+"it must be less than "+graph.getSize());
        else if (u == v) 
          JOptionPane.showMessageDialog(
              null, "Two vertices cannot be the same");
       else if (edgeslist.contains(new AbstractGraph.Edge(u,v)) || edgeslist.contains(new AbstractGraph.Edge(v,u)) ) {
			edgeslist.remove(new WeightedEdge(u,v,(int)weight));
			
       // else if (graph.addEdge(u, v)) {
        	//edgeslist.
        JOptionPane.showMessageDialog(jbtAddEdge, "contains "+u+v);
        }
        
        else {
          graph.addEdge(u, v, (int) weight);
          
          view.repaint();
          edgeslist.add(new WeightedEdge(u, v, (int) weight));
          edgeslist.add(new WeightedEdge(v, u, (int) weight));
          view.repaint();
          //JOptionPane.showMessageDialog(jbtAddEdge, "contains  graph add edge:"+u+v);

         // System.out.print("no of edges = " + edgeslist.size());

        }
       /* edgeslist.remove(new WeightedEdge(u,v,(int)weight));
        System.out.print("no of edges = " + edgeslist.size());
       */ view.repaint();
      }
    });     

  
    
    
    shrpath.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        int u = Integer.parseInt(shrstart.getText().trim());
        int v= Integer.parseInt(shrend.getText().trim());
        try {
        	  WeightedGraph<String> graph1 = 
        	  new WeightedGraph<String>(edgeslist, verticeslist.size());
        	   
        	 
        	  WeightedGraph<String>.ShortestPathTree tree1 = 
   			  graph1.getShortestPath(v);
        	  java.util.List<Integer> path = tree1.getPath1(u);
              view.setTree1(true,path,verticeslist);
        	  
        	  
        	
        	  
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
          view.repaint();
        }
        
      });   
    
    
    importing.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
         
        	 JFileChooser chooser = new JFileChooser();
			    
			    try {
			        
			        File f = new File(new File("filename.txt").getCanonicalPath());
			    
			        chooser.setSelectedFile(f);
			        }      catch (IOException e1) {
			        }
			    
			    		  
			      chooser.showOpenDialog(importing );
			    /*  int retval = chooser.showOpenDialog(importing);
               if (retval == JFileChooser.APPROVE_OPTION){
               */File field = chooser.getSelectedFile();
               c1.setText(field.getAbsolutePath());
               //}
          }
      });   
    
    
    export.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
         
        	 JFileChooser chooser = new JFileChooser();
			    
			    try {
					  
				      chooser.showSaveDialog(export);
				      //int retval = chooser.showSaveDialog(export);
	             /*  if (retval == JFileChooser.APPROVE_OPTION){*/
	               File field = chooser.getSelectedFile();
	               c1.setText(field.getAbsolutePath());
			        File f = new File(new File("filename.txt").getCanonicalPath());
			        java.io.PrintWriter output = new java.io.PrintWriter(field);
	                   
	                   int numberOfVertices = verticeslist.size();
	                   output.println("no of vertices present in the graph are:"+numberOfVertices);
		                   output.println("Vertices are:");
		                   for(int i=0;i<verticeslist.size();i++)
		                   {
		                   output.print(verticeslist.get(i).name+ ", " +verticeslist.get(i).x+ ", " +verticeslist.get(i).y);
		                   output.println();
		                   }
		                   output.println();
		                   output.println();

		                   
		                   int numberOfEdges = edgeslist.size();
		                   output.println("no of edges  present in the graph are:"+numberOfEdges);
		                   output.println("The Edges are:");
		                 
	                   for(int i=0;i<edgeslist.size();i++)
	                   {
	                   output.print(edgeslist.get(i).u+ ", " +edgeslist.get(i).v+ ", " +edgeslist.get(i).weight);
	                   output.println();
	                   }
	                  
	                   output.close();
	                   chooser.setSelectedFile(f);
			        }      catch (IOException e1) {
			        }
			    
			    /*		  
			      chooser.showSaveDialog(export);
			      //int retval = chooser.showSaveDialog(export);
               if (retval == JFileChooser.APPROVE_OPTION){
               File field = chooser.getSelectedFile();
               c1.setText(field.getAbsolutePath());*/
               JOptionPane.showMessageDialog(export, "Exported Succesfully....");
               
             //  }
          }
      }); 
    
    
    
    
    
  }
  
  class Vertex implements Displayable {
    private int x, y;
    private String name;
    
    Vertex(String name, int x, int y) {
      this.name = name;
      this.x = x;
      this.y = y;
    }
    
    public int getX() {
      return x;
    }
    
    public int getY() {
      return y;
    }
    
    public String getName() {
      return name;
    }
    
    public boolean equals(Object o) {
      return ((Vertex)o).name.equals(this.name);
    }
  }
  
  class GraphView extends javax.swing.JPanel {
	  
	  
	  boolean printShortesrtpath = false;	  
	  java.util.List<Integer> path1;
    Graph<? extends Displayable> graph;
    List<? extends Displayable> path;
    List<Vertex> vertices1;
    private AbstractGraph<? extends Displayable>.Tree tree;
    
    public GraphView(Graph<? extends Displayable> graph, 
        List<? extends Displayable> path) {
      this.graph = graph;
      this.path = path;
    }
    
    public GraphView(Graph<? extends Displayable> graph) {
      this.graph = graph;
    }

    public void setTree(AbstractGraph<? extends Displayable>.Tree tree) {
      this.tree = tree;
      repaint();
    }
    public void setTree1(boolean flag,java.util.List<Integer> path,List<Vertex> vertices) {
    	path1= path;
    	vertices1 = vertices;
    	printShortesrtpath = flag;
      }

    public void setPath(List<? extends Displayable> path) {
      this.path = path;
      repaint();
    }
    
    protected void paintComponent(java.awt.Graphics g) {
      super.paintComponent(g);
      
      // Draw vertices
      List<? extends Displayable> vertices = graph.getVertices();
      
      for (int i = 0; i < graph.getSize(); i++) {
        int x = vertices.get(i).getX();
        int y = vertices.get(i).getY();
        String name = vertices.get(i).getName();
        
        g.fillOval(x - 8, y - 8, 16, 16);
        g.drawString(name, x - 12, y - 12);
      }
      
      // Draw edges
      for (int i = 0; i < graph.getSize(); i++) {
        List<Integer> neighbors = graph.getNeighbors(i);
        for (int j = 0; j < neighbors.size(); j++) {
          int v = neighbors.get(j);
          int x1 = graph.getVertex(i).getX();
          int y1 = graph.getVertex(i).getY();
          int x2 = graph.getVertex(v).getX();
          int y2 = graph.getVertex(v).getY();
          
          g.drawLine(x1, y1, x2, y2);
        }
      }
      
      // Display weights
      List<PriorityQueue<WeightedEdge>> queues = 
        ((WeightedGraph<? extends Displayable>)graph).getWeightedEdges();    
      
      for (int i = 0; i < graph.getSize(); i++) {
        ArrayList<WeightedEdge> list = new ArrayList<WeightedEdge>(queues.get(i));
        
        for (WeightedEdge edge: list) {
          int u = edge.u;
          int v = edge.v;
          double weight = edge.weight;
          int x1 = graph.getVertex(u).getX();
          int y1 = graph.getVertex(u).getY();
          int x2 = graph.getVertex(v).getX();
          int y2 = graph.getVertex(v).getY();
          g.drawString(weight + "", (x1 + x2) / 2, (y1 + y2) / 2 - 6);
        }
      }
      if(printShortesrtpath)
      {
    	 /* if(tree ==null)
    	  {
    		  System.out.println("Done!");
    	  
    	  }*/
       if (path1!=null) {      
        g.setColor(java.awt.Color.RED);
        for (int i = 0; i < path1.size()-1; i++) {
          //  int v = tree.getParent(i);
            int x1 = vertices1.get(path1.get(i)).getX();
            int y1 = vertices1.get(path1.get(i)).getY();
            int x2 = vertices1.get(path1.get(i+1)).getX();
            int y2 = vertices1.get(path1.get(i+1)).getY();
            
            g.drawLine(x1, y1, x2, y2);  
          }
        
      }
      }
      // Highlight the edges in the spanning tree
      if (tree != null) {      
        g.setColor(java.awt.Color.RED);
        for (int i = 0; i < tree.getNumberOfVerticesFound(); i++) {
          if (tree.getParent(i) != -1) {
            int v = tree.getParent(i);
            int x1 = graph.getVertex(i).getX();
            int y1 = graph.getVertex(i).getY();
            int x2 = graph.getVertex(v).getX();
            int y2 = graph.getVertex(v).getY();
            
            g.drawLine(x1, y1, x2, y2);  
          }
        }
      }
        
      // Display the path
      if (path != null) {
        g.setColor(Color.RED);
        for (int i = 1; i < path.size(); i++) {
          int x1 = path.get(i).getX();
          int y1 = path.get(i).getY();
          int x2 = path.get(i - 1).getX();
          int y2 = path.get(i - 1).getY();
          g.drawLine(x1, y1, x2, y2);
        }
      }
    }
    
    public Dimension getPreferredSize() {
      return new Dimension(300, 500);
    }
  }
  
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    DynamicWeitedGraph applet = new DynamicWeitedGraph();
    frame.add(applet);
    frame.setTitle("DynamicWeitedGraph: Dynamic MST");
    //frame.setLocationRelativeTo();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}